/*
 * Assumptions:
 * 	1. If an item does not exist, it will not be reported in the response to a PROPFIND request.
 *  2. If a reference does not exist it will not be reported in the response to a PROPFIND request.
 */

var ItemCollection = new Class({
	initialize: function(xmlItemList) {
		var responses = new Array(xmlItemList.getElementsByTagName('D:response')).flatten();
			
		if (!responses || responses.length == 0)
			return null;
			
		this.url = (res = responses[0].getElementsByTagName('D:href')[0]) && res.textContent ? res.textContent : res.text;	
		this.items = responses.map(function(item) { return new Item(item) });
	}
});

var Item = new Class({
	initialize: function(item) {
		this.href = (el = item.getElementsByTagName('D:href')[0]) && el.textContent ? sharpbar.applicationUrl + el.textContent : sharpbar.applicationUrl + el.text;
		this.relationships = (rels = new Array(item.getElementsByTagName('mc:relation')).flatten()) ? rels.map(function(rel) { return {
			'url': rel.getAttribute('target'),
			'type': rel.getAttribute('type')
		}}) : [];
		this.references = (refs = new Array(item.getElementsByTagName('mc:reference')).flatten()) ? refs.map(function(ref) { return {
			'url': ref.getAttribute('source'),
			'type': ref.getAttribute('type')
		}}) : [];
	}
});

function verifyRels(reporter, propFindResponse, depth) {
	if (depth < 0 || propFindResponse == null)
		return;
		
	var ic = new ItemCollection(propFindResponse),
		currentUrl = (sharpbar.applicationUrl + ic.url).toLowerCase();
	
	ic.items.each(function(item) {
		if (item.relationships.length > 0 || item.references.length > 0) {
			item.relationships.combine(item.references).each(function(reference){
				referenceUrl = reference.url.toLowerCase();
				referenceType = reference.type;
				referenceKey = referenceUrl+referenceType;
				if (!reporter.validatedLinks.has(referenceKey)) { // If we've already checked the link's existence don't check it again
					reporter.validatedLinks[referenceKey] = false;
					mc.propfind(referenceUrl, function(results){
						reporter.validatedLinks[referenceKey] = true;
						return verifyRels(reporter, results, depth - 1);
					}, false, ['D:displayname', 'mc:mimetype', 'mc:resourceprovider', 'mc:version', 'mc:published', 'mc:name', 'mc:relationships'], null, true);
					if(reporter.relTypeFilter == "AllTypes" || referenceType == reporter.relTypeFilter)
						reporter.write([item.href.toLowerCase(), referenceUrl, referenceType, reporter.validatedLinks[referenceKey]], reporter.validatedLinks[referenceKey] ? '#DDDDDD' : '#FF0000');
				}
			});
		} else {
			// These are folders or items without ref/rels so we don't report on them...
			// TODO: Check to see if this makes a loop when run on Mac
			mc.propfind(item.href, function(results){
				return verifyRels(reporter, results, depth - 1);
			}, false, ['D:displayname', 'mc:mimetype', 'mc:resourceprovider', 'mc:version', 'mc:published', 'mc:name', 'mc:relationships'], null, true);
		}
	});
}

function parallelReport(url, depth) {
	mc.propfind(url, function(results) {
		if (depth < 0 || results == null)
			return;
		
		var ic = new ItemCollection(results),
			currentUrl = (sharpbar.applicationUrl + ic.url).toLowerCase(),
			partitionSize = parseInt(ic.items.length/8); // Pretty much just pulled out of thin air.
			
		ic.items.each(function(item) {
			var worker = new Worker(sharpbar.mediaUrl + "/Resources/lib/reports/report-worker.js");
			worker.onmessage = function(e) {
				var data = e.data;
				
				console.log(data.source, data.target, data.isValid);
			}
			worker.postMessage({'collection': ic, 'depth': depth});
		});
	}, true, ['D:displayname', 'mc:mimetype', 'mc:resourceprovider', 'mc:version', 'mc:published', 'mc:name', 'mc:relationships']);	
}

function startVerifyRels(reporter, url, depth) {
	// Prime the pump with the first set of results	
	mc.propfind(url, function(results) {
		// Pump away		
		reportDocument.writeln('<html><head><title>Relationships Report</title></head><body>');
		reportDocument.writeln('<table cellpadding="10" border="1">');
		reportDocument.writeln('<thead><tr><th>Source</th><th>Target</th><th>Type</th><th>Valid</th></tr></thead>');
		reportDocument.writeln('<tbody>');
		verifyRels(reporter, results, depth);
		reportDocument.writeln('</tbody>');
		reportDocument.writeln('<tfoot><tr><td></td><td></td><td></td><td></td></tr></tfoot>');
		reportDocument.writeln('</table>');
		reportDocument.writeln('</body></html>');
		reportDocument.close();
	}, true, ['D:displayname', 'mc:mimetype', 'mc:resourceprovider', 'mc:version', 'mc:published', 'mc:name', 'mc:relationships']);	
}

function report(url, depth, relTypeFilter) {
	this.reportWindow = window.open('about:blank', 'relationshipReportWindow'),
	this.reportDocument = this.reportWindow.document;
	this.reportDocument.open();
	var reporter = { 
		'validatedLinks': new Hash({}), 
		'write': function(record, color){
			if (color)
				reportDocument.writeln('<tr bgcolor=' + color + '>');
			else
				reportDocument.writeln('<tr>');
			record.each(function(cell) {
				reportDocument.writeln('<td>' + cell + '</td>');
			});
			reportDocument.writeln('</tr>');
		},
		'relTypeFilter': relTypeFilter
	};
	startVerifyRels(reporter, url, depth);
}

var Report = new Class({
	initialize: function() {
		
	},
	write: function(string) {
		
	}
});

// Reporting namespace
var Reporting = new Hash({
	// Report model
	Report: new Class({
		initialize: function(columnCount, headerValues) {
			this.data = new Array();
			this.columns = columnCount;
		},
		display: function() {
			
		},
		makeRow: function(values, rowEl, cellEl) {
			var row = new Element(rowEl ? rowEl : 'tr'),
				cellTag = cellEl ? cellEl : 'td';
				
			values.each(function(value) {
				row.grab(new Element(cellTag, { 'text': value}));
			});
		},
		addRow: function(values) {
			if (values != this.columnCount)
				return false;
				
			this.data.push(values);
		}
	})
});
